package wsepForum.domain.handlers;

import java.util.Vector;

import wsepForum.common.elements.*;
import wsepForum.common.elements.AForumElement.ForumElementType;
import wsepForum.domain.Session;
import wsepForum.domain.SessionManager;
import wsepForum.domain.exceptions.*;
import wsepForum.logging.ForumLogger;
import wsepForum.persistance.IPersistentHandler;
import wsepForum.persistance.exceptions.DataBaseIOException;

/**
 * The main interface between the GUI layer and the domain layer.
 * Provides the transportation of information between the GUI and the persistent.
 * Each further inheritance implements/overrides the services a certain user group
 * can receive from the system.
 *
 * This handler deals with a member user
 *
 * @author Amir Harel & Ariel Rozen & Oren Ben-Haim
 */
public class MemberHandler extends GuestHandler {

	/*****************************
	 * MEMBERS                   *
	 *****************************/
	/**
	 * An object that holds information about the logged-in user
	 */
	protected User user;

	/*****************************
	 * CONSTRUCTOR               *
	 *****************************/
	/**
	 * @param user An object that holds information about the logged-in user
	 * @param persistent The interface supplied by the persistent layer.
	 */
	public MemberHandler(User user, IPersistentHandler persistent) {
		super(persistent);
		this.user = user;
	}

	/*****************************
	 * METHODS                   *
	 *****************************/

	/* (non-Javadoc)
	 * @see wsepForum.domain.handlers.GuestHandler#addMessageToTopic(double, java.lang.String, java.lang.String)
	 */
	@Override
	public Topic addMessageToTopic(int topicID, String messageHeadline, String messageBody) throws Exception {
		Topic refreshedTopic = null;
		Message newMessage = new Message(messageHeadline,this.user.getUserName(),messageBody);
		this.getPersistent().setForumElement(topicID,  ForumElementType.TOPIC, newMessage);
		refreshedTopic = this.getTopic(topicID);

		ForumLogger.getInstance().info(this.getUser().getUserName() + " post message with headline " + messageHeadline + " in topic " + refreshedTopic.getHeadLine(),
				ForumLogger.LoggerCategory.DOMAIN);

		return refreshedTopic;
	}

	/* (non-Javadoc)
	 * @see wsepForum.domain.handlers.GuestHandler#createTopic(double, java.lang.String, java.lang.String)
	 */
	@Override
	public Topic createTopic(int sectionID, String messageHeadline, String messageBody) throws Exception {
		Topic refreshedTopic = null;
		int newTopicID;
		Message newFirstMessage = new Message(messageHeadline,this.user.getUserName(),messageBody);
		newTopicID = this.getPersistent().setForumElement(sectionID,  ForumElementType.SECTION, newFirstMessage);
		refreshedTopic = this.getTopic(newTopicID);

		ForumLogger.getInstance().info(this.getUser().getUserName() + " open topic with headline " + messageHeadline + " in section " + sectionID,
				ForumLogger.LoggerCategory.DOMAIN);

		return refreshedTopic;
	}

	/**
	 * Determines if the current user is allowed to edit a specific message
	 * user can edit is own messages.
	 * @param messageToEdit The message to edit
	 * @param sectionID the section which the message is in
	 * @return true, if allowed to edit the message
	 */
	public boolean editMessageAuthentication(Message messageToEdit, int sectionID) throws SystemFailureException{
		if((messageToEdit.getUserName() != null) && (messageToEdit.getUserName().equals(this.user.getUserName()))) return true;
		else return false;
	}

	/* (non-Javadoc)
	 * @see wsepForum.domain.handlers.GuestHandler#editMessage(double, double, java.lang.String, java.lang.String)
	 */
	@Override
	public Topic editMessage(int topicID, int messageToEditID, String messageHeadLine, String messageBody) throws Exception {
		Topic refreshedTopic = null;
		Message messageToEdit = this.getMessage(messageToEditID);
		refreshedTopic = this.getTopic(topicID);
		if (this.editMessageAuthentication(messageToEdit,refreshedTopic.getParentID())){
			messageToEdit.setHeadLine(messageHeadLine);
			messageToEdit.setBody(messageBody);
			this.getPersistent().setForumElement(topicID, ForumElementType.TOPIC, messageToEdit);
			refreshedTopic = this.getTopic(topicID);

			ForumLogger.getInstance().info(this.getUser().getUserName() + " edited message with headline " + messageToEdit.getHeadLine() + " in topic " + refreshedTopic.getHeadLine(),
					ForumLogger.LoggerCategory.DOMAIN);
		}
		else {
			ForumLogger.getInstance().error("ERROR: " + this.getUser().getUserName() + " trying to edit message with Headline " + messageToEdit.getHeadLine() + " but he is not authorized",
					ForumLogger.LoggerCategory.DOMAIN);

			throw new UnAuthorizedException();
		}
		return refreshedTopic;
	}


	/**
	 * determines if the user is authorized to delete the message
	 * @param messageToDelete - the message to delete
	 * @param sectionID - the section in which the message is in
	 * @return true if the user is authorized to delete
	 */
	public boolean deleteMessageAuthentication(Message messageToDelete, int sectionID) throws SystemFailureException {
		return (messageToDelete.getUserName() != null) && this.getUser().getUserName().equals(messageToDelete.getUserName());

	}

	/* (non-Javadoc)
	 * @see wsepForum.domain.handlers.AUserHandler#deleteMessage(int)
	 */
	@Override
	public AForumElement deleteMessage(int parentTopicID, int messageToDeleteID) throws Exception {
		AForumElement refreshedElement = null;
		Message messageToDelete = this.getMessage(messageToDeleteID);
		refreshedElement = this.getPersistent().getForumElement(parentTopicID, ForumElementType.TOPIC);
		if (this.deleteMessageAuthentication(messageToDelete,refreshedElement.getParentID())){

			refreshedElement = this.getPersistent().deleteForumElement(messageToDeleteID, ForumElementType.MESSAGE);
			ForumLogger.getInstance().info(this.getUser().getUserName() + " deleted message with Headline " + messageToDelete.getHeadLine() +
					" in topic " + messageToDelete.getParentID(), ForumLogger.LoggerCategory.DOMAIN);
		}
		else{
			ForumLogger.getInstance().error("ERROR: " + this.getUser().getUserName() + " trying to delete message with Headline " + messageToDelete.getHeadLine() + " but he is not authorized",
					ForumLogger.LoggerCategory.DOMAIN);
			throw new UnAuthorizedException();
		}
		return refreshedElement;

	}

	/* (non-Javadoc)
	 * @see wsepForum.domain.handlers.GuestHandler#login(java.lang.String, java.lang.String)
	 */
	@Override
	public AUserHandler login(String userName, String password) throws UnAuthorizedException {
		throw new UnAuthorizedException();
	}

	/* (non-Javadoc)
	 * @see wsepForum.domain.handlers.GuestHandler#logout()
	 */
	@Override
	public AUserHandler logout(Session session) throws UnAuthorizedException, NoSuchUserSessionExcepion, SystemFailureException {
		try {
			if(SessionManager.getInstance().removeUserSession(this.user.getUserName(),session)){
				ForumLogger.getInstance().info(this.getUser().getUserName() + " looged out", ForumLogger.LoggerCategory.DOMAIN);
				this.getPersistent().logout(this.user.getUserName());
			}
		} catch (DataBaseIOException e) {
			throw new SystemFailureException(e);
		}
		return new GuestHandler(this.getPersistent());
	}

	/* (non-Javadoc)
	 * @see wsepForum.domain.handlers.GuestHandler#register(java.lang.String, java.lang.String)
	 */
	@Override
	public boolean register(String userName, String password) throws UnAuthorizedException {
		throw new UnAuthorizedException();
	}

	/**
	 * determines if the user is authorized to unregister\ban the user
	 * @param userName - the user to unregister\ban
	 * @return if the current user is authorized
	 * @throws Exception
	 */
	protected boolean removeUserAuthentication(String userName) throws Exception{
		return userName != "admin" && this.getUser().getUserName().equals(userName);
	}

	/* (non-Javadoc)
	 * @see wsepForum.domain.handlers.AUserHandler#removeUser(java.lang.String)
	 */
	@Override
	public boolean removeUser(String userName) throws Exception {
		if(this.removeUserAuthentication(userName)){
			
			// remove the user from all the sections he is moderator in
			User userToRemove = this.getPersistent().getUser(userName);
			for (Integer sectionID : userToRemove.getAllSections()) {
				
				Section sectionToEdit = this.getSection(sectionID);
				sectionToEdit.removeSectionMod(userName);
				this.getPersistent().setForumElement(sectionToEdit.getParentID(), ForumElementType.SECTION, sectionToEdit);
				
				
				ForumLogger.getInstance().info(userName + " lost his Moderator privelige in " + sectionToEdit.getHeadLine()
						,ForumLogger.LoggerCategory.DOMAIN);
			}
			SessionManager.getInstance().notifyUserChange(userName);
			this.getPersistent().deleteUser(userName);

			ForumLogger.getInstance().info(userName + " was deleted from the system", ForumLogger.LoggerCategory.DOMAIN);
			
			return true;
		}
		else{
			ForumLogger.getInstance().error("ERROR: " + this.getUser().getUserName() + " trying to delete user " + userName + " but he is not authorized",
					ForumLogger.LoggerCategory.DOMAIN);
			throw new UnAuthorizedException();
		}
	}
	
	@Override
	public boolean changePassword(String oldPass, String newPass) throws Exception {
		if(this.getPersistent().login(this.getUser().getUserName(), oldPass)){
			this.getUser().setPassword(newPass);
			return this.getPersistent().setUser(this.getUser());
			}
		else throw new WrongPasswordException(); 
	}
	

	@Override
	public Vector<String> getManagedUsernames() {
		Vector<String> userList = new Vector<String>();
		userList.add(this.getUser().getUserName());
		return userList;
	}

	/**
	 * @return An object that holds information about the logged-in user
	 */
	public User getUser() {
		return this.user;
	}

}